package cn.getech.data.development.service.impl;


import cn.getech.data.development.constant.PermissionTypeEnum;
import cn.getech.data.development.entity.TableFieldInfo;
import cn.getech.data.development.entity.TableInfo;
import cn.getech.data.development.entity.permission.*;
import cn.getech.data.development.mapper.TableInfoMapper;
import cn.getech.data.development.mapper.permission.SysRoleDataPermissionMapper;
import cn.getech.data.development.mapper.permission.SysTenantDataPermissionMapper;
import cn.getech.data.development.service.DataPermissionService;
import cn.getech.data.development.service.RangerDataService;
import cn.getech.data.development.service.TableInfoService;
import cn.getech.data.development.utils.DataPermissionUtil;
import cn.getech.system.center.entity.SysRoleEntity;
import cn.getech.system.center.mapper.SysRoleMapper;
import cn.getech.system.center.service.SysRoleService;
import cn.getech.system.center.utils.ShiroUtils;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @description: 数据权限处理类
 * @author: wangzhaowen：kiss
 * @create: 2020/8/4 17:58
 * @version: 2020/8/4
 **/
@Slf4j
@Service
public class DataPermissionServiceImpl implements DataPermissionService {
    @Autowired
    private SysRoleDataPermissionMapper sysRoleDataPermissionMapper;

    @Autowired
    private SysTenantDataPermissionMapper sysTenantDataPermissionMapper;

    @Autowired
    private TableInfoMapper tableInfoMapper;
    @Autowired
    private TableInfoService tableInfoService;
    @Autowired
    private SysRoleService sysRoleService;

    @Autowired
    private SysRoleMapper sysRoleMapper;

    @Override
    public void savePermission(List<SysRoleDataPermission> permissionList) {
        if (CollectionUtils.isNotEmpty(permissionList)) {
            List<SysRoleDataPermission> addList = new ArrayList<>();
            List<SysRoleDataPermission> updateList = new ArrayList<>();
            for (SysRoleDataPermission sysRoleDataPermission : permissionList) {
                if (sysRoleDataPermission.getId() != null) {
                    updateList.add(sysRoleDataPermission);
                } else {
                    addList.add(sysRoleDataPermission);
                }
            }
            if (CollectionUtils.isNotEmpty(addList)) {
                try {
                    sysRoleDataPermissionMapper.batchInsert(addList);
                } catch (DuplicateKeyException e) {//若果存在重复的数据  需要逐条插入或者更新
                    for (SysRoleDataPermission sysRoleDataPermission : addList) {
                        sysRoleDataPermissionMapper.insertOrUpdateSelective(sysRoleDataPermission);
                    }
                }
            }
            if (CollectionUtils.isNotEmpty(updateList)) {
                sysRoleDataPermissionMapper.updateBatch(updateList);
            }
        }
    }

    @Override
    public void saveTenantPermission(List<SysTenantDataPermission> permissionList) {
        if (CollectionUtils.isNotEmpty(permissionList)) {
            List<SysTenantDataPermission> addList = new ArrayList<>();
            List<SysTenantDataPermission> updateList = new ArrayList<>();
            for (SysTenantDataPermission sysTenantDataPermission : permissionList) {
                if (sysTenantDataPermission.getId() != null) {
                    updateList.add(sysTenantDataPermission);
                } else {
                    addList.add(sysTenantDataPermission);
                }
            }
            if (CollectionUtils.isNotEmpty(addList)) {
                try {
                    sysTenantDataPermissionMapper.batchInsert(addList);
                } catch (DuplicateKeyException e) {//若果存在重复的数据  需要逐条插入或者更新
                    for (SysTenantDataPermission sysTenantDataPermission : addList) {
                        sysTenantDataPermissionMapper.insertOrUpdateSelective(sysTenantDataPermission);
                    }
                }
            }
            if (CollectionUtils.isNotEmpty(updateList)) {
                sysTenantDataPermissionMapper.updateBatch(updateList);
                for (SysTenantDataPermission sysTenantDataPermission : updateList) {
                    List<SysRoleEntity> roles = sysRoleMapper.queryRoleEntityListByTenantId(sysTenantDataPermission.getTenantId());
                    if (CollectionUtils.isNotEmpty(roles)) {
                        List<Long> roleIds = roles.stream().map(i -> i.getRoleId()).collect(Collectors.toList());
                        SysRoleDataPermissionExample param = new SysRoleDataPermissionExample();
                        param.createCriteria().andRoleIdIn(roleIds).andDataIdEqualTo(Long.valueOf(sysTenantDataPermission.getDataId())).andDataTypeEqualTo(sysTenantDataPermission.getDataType());
                        List<SysRoleDataPermission> dataPermissions = sysRoleDataPermissionMapper.selectByExample(param);
                        if (CollectionUtils.isNotEmpty(dataPermissions)) {
                            //当取消对租户授权时，收回该租户下所有角色对该数据权限
                            boolean cancel = false;
                            for (SysRoleDataPermission sysRoleDataPermission : dataPermissions) {
                                if (sysTenantDataPermission.getQuery()!=null&&sysTenantDataPermission.getQuery() == 0) {
                                    cancel = true;
                                    sysRoleDataPermission.setQuery(0);
                                }
                                if (sysTenantDataPermission.getAssign()!=null&&sysTenantDataPermission.getAssign() == 0) {
                                    cancel = true;
                                    sysRoleDataPermission.setAssign(0);
                                }
                                if (sysTenantDataPermission.getCreate()!=null&&sysTenantDataPermission.getCreate() == 0) {
                                    cancel = true;
                                    sysRoleDataPermission.setCreate(0);
                                }
                                if (sysTenantDataPermission.getDecrypt()!=null&&sysTenantDataPermission.getDecrypt() == 0) {
                                    cancel = true;
                                    sysRoleDataPermission.setDecrypt(0);
                                }
                                if (sysTenantDataPermission.getDelete()!=null&&sysTenantDataPermission.getDelete() == 0) {
                                    cancel = true;
                                    sysRoleDataPermission.setDelete(0);
                                }
                                if (sysTenantDataPermission.getExport()!=null&&sysTenantDataPermission.getExport() == 0) {
                                    cancel = true;
                                    sysRoleDataPermission.setExport(0);
                                }
                                if (sysTenantDataPermission.getUpdate()!=null&&sysTenantDataPermission.getUpdate() == 0) {
                                    cancel = true;
                                    sysRoleDataPermission.setUpdate(0);
                                }
                                if (sysTenantDataPermission.getWrite()!=null&&sysTenantDataPermission.getWrite() == 0) {
                                    cancel = true;
                                    sysRoleDataPermission.setWrite(0);
                                }
                            }
                            if (cancel) {
                                sysRoleDataPermissionMapper.updateBatch(dataPermissions);
                            }
                        }
                    }
                }
            }
        }
    }

    @Override
    public void deleteTenantPermission(Integer dataId, Integer dataType) {
        sysTenantDataPermissionMapper.deleteByDataId(dataId, dataType);
    }

    @Override
    public boolean checkDataPermission(Integer id, Integer dataType, Integer operation) {
        Long userId = ShiroUtils.getUserId();
        Integer tenantId = ShiroUtils.getTenantId();
        //租户管理员特殊处理
        if (sysRoleService.isSuperAdmin(userId)) {
            Integer createTenantId = sysTenantDataPermissionMapper.getCreateTenantId(id, dataType);
            if (tenantId != null && tenantId.equals(createTenantId)) {
                return true;
            }
        }
        List<Integer> ids = DataPermissionUtil.getDataIds(
                userId.intValue(), dataType, operation);
        if (PermissionTypeEnum.STORE.getType().equals(dataType)) {
            ids.addAll(DataPermissionUtil.getApplyDataIds(userId, operation));
        }
        if (PermissionTypeEnum.REAL_TABLE.getType().equals(dataType)) {
            ids.addAll(DataPermissionUtil.getApplyRealTableDataIds(userId, operation));
        }
        if (CollectionUtils.isNotEmpty(ids)) {
            if (!ids.contains(id)) {
                return false;
            }
        } else {
            return false;
        }
        return true;
    }

    @Override
    public boolean checkApplyRealPermission(Integer id, Integer operation) {
        Long userId = ShiroUtils.getUserId();
        List<Integer> ids = DataPermissionUtil.getApplyRealTableDataIds(
                userId, operation);
        if (CollectionUtils.isNotEmpty(ids)) {
            if (!ids.contains(id)) {
                return false;
            }
        } else {
            return false;
        }
        return true;
    }

    @Override
    public boolean checkApplyPermission(Integer id, Integer operation) {
        Long userId = ShiroUtils.getUserId();
        List<Integer> ids = DataPermissionUtil.getApplyDataIds(
                userId, operation);
        if (CollectionUtils.isNotEmpty(ids)) {
            if (!ids.contains(id)) {
                return false;
            }
        } else {
            return false;
        }
        return true;
    }

    @Override
    public boolean checkDataPermission(List<Integer> dataIds, Integer dataType, Integer operation) {
        Long userId = ShiroUtils.getUserId();
        List<Integer> needIds = new ArrayList<>();
        Integer tenantId = ShiroUtils.getTenantId();
        for (Integer dataId : dataIds) {
            if (sysRoleService.isSuperAdmin(userId)) {
                Integer createTenantId = sysTenantDataPermissionMapper.getCreateTenantId(dataId, dataType);
                if (tenantId != null && !tenantId.equals(createTenantId)) {
                    needIds.add(dataId);
                }
            } else {
                needIds.add(dataId);
            }
        }
        List<Integer> ids = DataPermissionUtil.getDataIds(
                userId.intValue(), dataType, operation);
        if (PermissionTypeEnum.REAL_TABLE.getType().equals(dataType)) {
            ids.addAll(DataPermissionUtil.getApplyRealTableDataIds(userId, operation));
        }
        if (PermissionTypeEnum.STORE.getType().equals(dataType)) {
            ids.addAll(DataPermissionUtil.getApplyDataIds(userId, operation));
        }
        if (CollectionUtils.isNotEmpty(ids)) {
            if (!ids.containsAll(needIds)) {
                return false;
            }
        } else {
            return false;
        }
        return true;
    }

    @Override
    public void initDataPermission(Integer id, Integer dataType, Integer userId, Long roleId) {
        //如果是租户管理员，则需要查询到这个租户管理员下的角色
        boolean admin = DataPermissionUtil.isAdmin(userId);
        List<Long> roleIds = null;
        if (admin) {
            List<SysRoleEntity> sysRoleEntities = sysRoleService.queryUserInfoByTenantId(ShiroUtils.getTenantId(), Long.valueOf(userId));
            if (CollectionUtil.isNotEmpty(sysRoleEntities)) {
                roleIds = sysRoleEntities.stream().map(SysRoleEntity::getRoleId).collect(Collectors.toList());
            }
        } else {
            roleIds = sysRoleDataPermissionMapper.queryUserRole(userId);
        }
        if (CollectionUtils.isNotEmpty(roleIds)) {
            if (null == roleId) {
                roleId = roleIds.get(0);
            }
            List<SysRoleDataPermission> permissionList = new ArrayList<>(1);
            SysRoleDataPermission dataPermission = new SysRoleDataPermission();
            dataPermission.yesValue(roleId, id, dataType);
            permissionList.add(dataPermission);
            savePermission(permissionList);
        }
    }

    @Autowired
    private RangerDataService rangerDataService;

    @Override
    public void initPermission(List<InitPermission> dataList) {
        Set<String> intiCreateTable = Sets.newHashSet();//初始化表创建者的权限

        for (InitPermission initPermission : dataList) {
            Long roleId = sysRoleDataPermissionMapper.selectRoleByName(initPermission.getRoleName());
            if (CollectionUtil.isNotEmpty(initPermission.getTableInfos())
                    && roleId != null) {
                List<TableInfoPermission> dataPermissionList = new ArrayList<>();
                for (TableInfo tableInfo : initPermission.getTableInfos()) {
                    TableInfo tableTemp = tableInfoMapper.selectTableByName(tableInfo.getDbName().trim(),
                            tableInfo.getTableName().trim());
                    if (tableTemp != null) {
                        TableInfo table = tableInfoService.getTableById(tableTemp.getId());
                        intiCreateTable.add(table.getDbName() + "|" + table.getTableName() + "|" + table.getId() + "|" + table.getCreatePer());
                        SysRoleDataPermission permission = new SysRoleDataPermission();
                        permission.yesValue(roleId, table.getId(), PermissionTypeEnum.STORE.getType());
                        TableInfoPermission tablePermission = new TableInfoPermission(table, permission);
                        tablePermission.setEnName(table.getTableName());
                        tablePermission.setChName(table.getTableAlias());
                        if (CollectionUtil.isNotEmpty(table.getTableFieldInfos())) {
                            List<TableFieldInfoPermission> fieldPermissionList = new ArrayList<>();
                            for (TableFieldInfo tableFieldInfo : table.getTableFieldInfos()) {
                                SysRoleDataPermission sp = new SysRoleDataPermission();
                                sp.yesValue(roleId, tableFieldInfo.getId(), PermissionTypeEnum.STORE_FILED.getType());
                                TableFieldInfoPermission fp = new TableFieldInfoPermission(tableFieldInfo, sp);
                                fp.setChName(tableFieldInfo.getFieldName());
                                fp.setEnName(tableFieldInfo.getFieldName());
                                fieldPermissionList.add(fp);
                            }
                            tablePermission.setTableFieldInfos(fieldPermissionList);
                        }
                        dataPermissionList.add(tablePermission);

                    } else {
                        log.warn("表库中不存在! {}:{}", tableInfo.getDbName(),
                                tableInfo.getTableName());
                    }
                }
                if (CollectionUtil.isNotEmpty(dataPermissionList)) {
                    log.info("初始角色{}:{}个策略中...", initPermission.getRoleName(), dataPermissionList.size());
                    tableInfoService.savePermission(dataPermissionList);
                    log.info("初始角色{}:{}个策略完成", initPermission.getRoleName(), dataPermissionList.size());
                }
            }
        }
        log.info("初始表的创建者{}个策略中...", intiCreateTable.size());
        rangerDataService.intiCreateTable(intiCreateTable);
        log.info("初始表的创建者{}个策略完成", intiCreateTable.size());
        log.info("初始表的创建者表:\n{}", JSONObject.toJSONString(intiCreateTable));
    }

    /**
     * @param dataIds
     */
    @Override
    public void saveOrUpdatePermission(List<Long> dataIds, Long roleId) {
        if (CollectionUtils.isEmpty(dataIds)) {
            return;
        }
        for (Long dataId : dataIds) {
            SysRoleDataPermission sysRoleDataPermission = sysRoleDataPermissionMapper.selectByRoleId(PermissionTypeEnum.METADATA_MANAGEMENT.getType(), dataId.intValue(), roleId);
            if (Objects.isNull(sysRoleDataPermission)) {
                sysRoleDataPermission = new SysRoleDataPermission();
                sysRoleDataPermission.setAssign(1);
                sysRoleDataPermission.setCreate(1);
                sysRoleDataPermission.setDecrypt(1);
                sysRoleDataPermission.setDelete(1);
                sysRoleDataPermission.setExport(1);
                sysRoleDataPermission.setUpdate(1);
                sysRoleDataPermission.setQuery(1);
                sysRoleDataPermission.setWrite(1);
                sysRoleDataPermission.setDataId(dataId.intValue());
                sysRoleDataPermission.setDataType(PermissionTypeEnum.METADATA_MANAGEMENT.getType());
                sysRoleDataPermission.setRoleId(roleId);
                sysRoleDataPermissionMapper.insertOrUpdateSelective(sysRoleDataPermission);
            } else {
                sysRoleDataPermission.setAssign(1);
                sysRoleDataPermission.setCreate(1);
                sysRoleDataPermission.setDecrypt(1);
                sysRoleDataPermission.setDelete(1);
                sysRoleDataPermission.setExport(1);
                sysRoleDataPermission.setUpdate(1);
                sysRoleDataPermission.setQuery(1);
                sysRoleDataPermission.setWrite(1);
                sysRoleDataPermissionMapper.insertOrUpdateSelective(sysRoleDataPermission);
            }
        }
    }
}

